package org.agent.aigccore.middleware.modbus.client;

import com.google.common.base.Joiner;
import com.serotonin.modbus4j.ModbusMaster;
import lombok.extern.slf4j.Slf4j;
import org.agent.aigccore.basic.Global;
import org.agent.aigccore.basic.exception.ResultCode;
import org.agent.aigccore.basic.validation.AssertUtils;
import org.agent.aigccore.middleware.modbus.helper.TasModbusHelper;
import org.agent.aigccore.model.bo.IotDeviceBO;

import java.util.concurrent.TimeUnit;

/**
 * @author moshihong
 * @version TasRegisterClient.java, v 0.1 2025年09月03日 09:31 moshihong
 */
@Slf4j
public class TasRegisterClient {

    // 塔石寄存器定义（1基地址）
    // 注册包模式（0：明文；1：加密）
    public static final int REG_REGISTER_MODE = 41;
    // 注册包长度（字节数）
    public static final int REG_REGISTER_LEN = 42;
    // 注册包内容（字符串）
    public static final int REG_REGISTER_CONTENT = 43;
    // 心跳模式（0：简单；1：带时间戳）
    public static final int REG_HEARTBEAT_MODE = 44;
    // 心跳包长度（字节数）
    public static final int REG_HEARTBEAT_LEN = 45;
    // 心跳包内容（字符串）
    public static final int REG_HEARTBEAT_CONTENT = 46;

    public void register(IotDeviceBO deviceBO) {
        AssertUtils.assertNotNull(deviceBO, "设备信息不能为空");
        AssertUtils.assertNotBlank(deviceBO.getDeviceIp(), "设备IP不能为空");
        AssertUtils.assertNotBlank(deviceBO.getDevicePort(), "设备端口不能为空");

        Boolean isRegistered = Boolean.FALSE;
        try {
            log.info("[TAS注册] 开始注册设备:{}|{}|{}", deviceBO.getDeviceName(), deviceBO.getDeviceIp(), deviceBO.getDevicePort());

            // 1）链接设备
            ModbusMaster tcpMaster = TasModbusHelper.connectModbus(deviceBO.getDeviceIp()
                    , Integer.parseInt(deviceBO.getDevicePort()));
            AssertUtils.assertNotNull(tcpMaster, "设备连接失败");
            log.info("[TAS注册] 连接DONE! tcpMaster={}", tcpMaster);

            // 2）读取设备配置
            // 读取：注册-寄存器信息
            Number regMode = TasModbusHelper.readRegister(tcpMaster, REG_REGISTER_MODE);
            Number regDataLen = TasModbusHelper.readRegister(tcpMaster, REG_REGISTER_MODE);
            log.info("[TAS注册] load配置DONE!模式：{},长度：{}", regMode, regDataLen);

            // 读取：心跳-寄存器信息
            Number hbMode = TasModbusHelper.readRegister(tcpMaster, REG_HEARTBEAT_MODE);
            Number hbDataLen = TasModbusHelper.readRegister(tcpMaster, REG_HEARTBEAT_LEN);
            log.info("[TAS注册] heartbeat配置DONE!模式：{},长度：{}", hbMode, hbDataLen);

            // 3）注册设备
            String registerContent = Joiner.on(Global.VERTICAL_LINE).join(deviceBO.getDeviceIp(), deviceBO.getDevicePort());
            AssertUtils.assertTrue(registerContent.getBytes().length < regDataLen.intValue()
                    , ResultCode.BIZ_ERROR, "注册内容长度超出限制!", String.valueOf(registerContent.getBytes().length));
            AssertUtils.assertTrue(registerContent.getBytes().length < hbDataLen.intValue()
                    , ResultCode.BIZ_ERROR, "心跳内容长度超出限制!", String.valueOf(registerContent.getBytes().length));
            log.info("[TAS注册] 即将注册设备，注册内容:{}", registerContent);
            TasModbusHelper.writeRegister(tcpMaster, REG_REGISTER_CONTENT, registerContent);

            // 核实注册状态
            TimeUnit.MILLISECONDS.sleep(500);
            Number regStatus = TasModbusHelper.readRegister(tcpMaster, REG_REGISTER_MODE);
            log.info("[TAS注册] 注册完成，CHECK状态!{}", regStatus);
            isRegistered = 1 == regStatus.intValue();
            AssertUtils.assertTrue(isRegistered, ResultCode.BIZ_ERROR
                    , "设备注册失败!{0}|{1}", deviceBO.getDeviceIp(), deviceBO.getDevicePort());
            log.info("[TAS注册] 注册完成!{}", isRegistered);

            // 启动心跳任务, 通过TASKFLOW来实现
            Number heartBeatStatus = TasModbusHelper.readRegister(tcpMaster, REG_HEARTBEAT_MODE);
            AssertUtils.assertTrue(1 == heartBeatStatus.intValue(), ResultCode.BIZ_ERROR
                    , "设备心跳功能未启用!{0}|{1}", deviceBO.getDeviceIp(), deviceBO.getDevicePort());
            log.info("[TAS注册] 设备心跳功能已启用!{}", heartBeatStatus);
        } catch (Throwable e) {
            log.error("[TAS注册] 失败!{0}|{1}", deviceBO.getDeviceIp(), deviceBO.getDevicePort(), e);
        }
    }


}
